<template>
  <div class="audio-player">
    <div class="controls-container">
      <div class="player-controls">
        <el-button
          :type="isPlaying ? 'danger' : 'primary'"
          :icon="isPlaying ? 'VideoPause' : 'VideoPlay'"
          :loading="isLoading"
          @click="handlePlayControl"
          circle
        />

        <el-slider
          v-model="progress"
          :max="100"
          :format-tooltip="formatProgress"
          :disabled="!isAudioLoaded"
          @input="handleSeek"
          class="progress-bar"
        />

        <div class="time-display">{{ formatTime(currentTime) }} / {{ formatTime(duration) }}</div>
      </div>

      <el-alert
        v-if="errorMessage"
        :title="errorMessage"
        type="error"
        show-icon
        class="error-alert"
      />
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, onUnmounted, watch } from 'vue'
import axios from 'axios'
import { base64ToBlob, createAudioElement, playAudio, cleanupAudio } from '@/utils/audioUtils'

const audioElement = ref<HTMLAudioElement | null>(null)
const isPlaying = ref(false)
const currentTime = ref(0)
const duration = ref(0)
const progress = ref(0)
const isLoading = ref(false)
const errorMessage = ref('')
const isAudioLoaded = ref(false)
const latestURL = ref<string | null>(null)
const lastInputHash = ref('') // 记录输入哈希

const props = defineProps({
  inputText: {
    type: String,
    required: true,
  },
  repeat: {
    type: Number,
    default: 1,
    required: false,
  },
})

// 在子组件script setup中添加
watch(
  () => props.inputText,
  async (newText, oldText) => {
    if (newText === oldText) return

    // 清理旧音频
    await handleAudioEnd()
    if (audioElement.value) {
      audioElement.value.removeEventListener('timeupdate', updateProgress)
      audioElement.value.removeEventListener('ended', handleAudioEnd)
    }

    // 加载新音频
    try {
      await fetchAudioURL()
    } catch (error) {
      handleError(error)
    }
  },
)

// 文本哈希生成函数
const hashString = (str: string): string => {
  let hash = 0
  for (let i = 0; i < str.length; i++) {
    hash = (Math.imul(31, hash) + str.charCodeAt(i)) | 0
  }
  return hash.toString(16)
}

const updateProgress = () => {
  if (!audioElement.value) return // 添加保护
  // 增加边界检查
  const timeDifference = Math.abs(audioElement.value.duration - audioElement.value.currentTime)
  if (timeDifference < 0.05) {
    // 小于100ms时强制结束
    handleAudioEnd()
    return
  }
  currentTime.value = Number(audioElement.value.currentTime.toFixed(2))
  progress.value = (currentTime.value / (duration.value || 1)) * 100 // 防止除零
}

// 修改handleAudioEnd函数
const handleAudioEnd = () => {
  if (!audioElement.value) return

  // 立即停止播放并重置
  audioElement.value.pause()
  audioElement.value.currentTime = 0
  isPlaying.value = false
  currentTime.value = 0
  progress.value = 0

  // 清理资源（重要）
  if (latestURL.value) {
    URL.revokeObjectURL(latestURL.value)
    latestURL.value = null
  }

  // 清理音频元素
  if (audioElement.value) {
    audioElement.value.removeEventListener('timeupdate', updateProgress)
    audioElement.value.removeEventListener('ended', handleAudioEnd)
    audioElement.value.src = ''
    audioElement.value.load()
    audioElement.value = null
  }
}

// 文件位置：替换原fetchAudioURL函数
const fetchAudioURL = async () => {
  // 清理旧的音频元素和URL
  if (audioElement.value) {
    cleanupAudio(audioElement.value, latestURL.value || undefined)
    audioElement.value = null
  }

  if (latestURL.value) {
    URL.revokeObjectURL(latestURL.value)
    latestURL.value = null
  }

  try {
    // 新增：重置状态
    isLoading.value = true
    errorMessage.value = ''
    isAudioLoaded.value = false
    currentTime.value = 0
    progress.value = 0

    // 获取base64编码的语音数据
    const response = await axios.post(
      '/api/audio/base64?' + 'text=' + props.inputText + '&repeat=' + props.repeat,
    )
    const base64Audio = response.data

    // 创建一个 Blob 对象
    const audioBlob = base64ToBlob(base64Audio, 'audio/mp3')

    // 创建一个新的 URL 对象
    latestURL.value = URL.createObjectURL(audioBlob)
    lastInputHash.value = hashString(props.inputText)
    console.log('[fetchAudioURL] 生成Blob URL', {
      url: latestURL.value,
      tip: '可复制此URL到浏览器地址栏验证是否可播放',
    })

    // 使用工具函数创建音频元素
    audioElement.value = await createAudioElement(latestURL.value, {
      timeout: 10000,
    })

    // 添加事件监听器
    audioElement.value.addEventListener('timeupdate', updateProgress)
    audioElement.value.addEventListener('ended', handleAudioEnd)
    /*audioElement.value.addEventListener('error', (e) => {
      console.error('Audio error:', e)
      handleError(new Error('音频加载失败'))
    })*/

    // 等待元数据加载
    duration.value = Number(audioElement.value!.duration.toFixed(2)) || 0 // 保留两位小数
    isAudioLoaded.value = true

    console.log('Audio loaded successfully')
  } catch (error) {
    handleError(error)
    throw error
  } finally {
    isLoading.value = false
  }
}

const handlePlayControl = async () => {
  try {
    // 暂停逻辑
    if (isPlaying.value && audioElement.value) {
      audioElement.value.pause()
      isPlaying.value = false
      return
    }

    // 播放逻辑
    const currentHash = hashString(props.inputText)

    // 判断是否需要重新获取音频
    if (!audioElement.value || !latestURL.value || currentHash !== lastInputHash.value) {
      await fetchAudioURL()
    }

    // 执行播放
    if (audioElement.value && audioElement.value.readyState >= HTMLMediaElement.HAVE_METADATA) {
      await playAudio(audioElement.value)
      isPlaying.value = true
    } else {
      throw new Error('音频未准备好播放')
    }
  } catch (error) {
    handleError(error)
    isPlaying.value = false
  }
}

// 进度跳转
const handleSeek = (percent: number) => {
  if (!audioElement.value || !duration.value) return
  const seconds = (percent / 100) * duration.value
  audioElement.value.currentTime = seconds
}

// 错误处理
const handleError = (error: Error | unknown) => {
  let message = '音频请求失败，请稍后重试'

  if (error instanceof Error) {
    message = error.message
  } else if (typeof error === 'object' && error !== null && 'response' in error) {
    const responseError = error as { response?: { data?: { message?: string } } }
    message = responseError.response?.data?.message || message
  }

  errorMessage.value = message
  console.error('音频播放错误:', error)
}

// 时间格式化
const formatTime = (seconds: number): string => {
  if (isNaN(seconds)) return '00:00'
  const mins = Math.floor(seconds / 60)
  const secs = Math.floor(seconds % 60)
  return `${String(mins).padStart(2, '0')}:${String(secs).padStart(2, '0')}`
}

// 进度提示格式化
const formatProgress = (percent: number): string => {
  const seconds = (percent / 100) * duration.value
  return formatTime(seconds)
}

// 修改onUnmounted
onUnmounted(() => {
  // 停止播放
  if (audioElement.value) {
    cleanupAudio(audioElement.value, latestURL.value || undefined)
    audioElement.value = null
  }

  // 清理 Blob URL
  if (latestURL.value) {
    URL.revokeObjectURL(latestURL.value)
    latestURL.value = null
  }
})
</script>
<style scoped>
.audio-player {
  width: 100%;
  max-width: 800px;
  margin: 20px auto;
  padding: 20px;
  background: #f5f7fa;
  border-radius: 8px;
}

.controls-container {
  display: flex;
  flex-direction: column;
  gap: 15px;
}

.input-box {
  margin-bottom: 20px;
}

.player-controls {
  display: flex;
  align-items: center;
  gap: 15px;
}

.progress-bar {
  flex: 1;
  margin: 0 10px;
}

.time-display {
  min-width: 100px;
  font-size: 14px;
  color: #606266;
}

.error-alert {
  margin-top: 10px;
}

.el-button {
  transition: all 0.3s ease;
}
</style>
